import cgi
from datetime import datetime
import estedt
import logging
import urllib
import webapp2
import re
import sys
import time

from google.appengine.ext import db
from google.appengine.api import users

import jinja2
import os

jinja_environment = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.path.dirname(__file__)))

# ===========================================================================
class Person(db.Model):
    """
    A person, a group member or leader.
    """
    p_firstname = db.StringProperty()
    p_lastname = db.StringProperty()
    p_phone = db.PhoneNumberProperty()
    p_email = db.EmailProperty()
    p_username = db.StringProperty()
    p_role = db.StringListProperty()
    
    p_updater = db.UserProperty(auto_current_user=True)
    p_updated = db.DateTimeProperty(auto_now=True)

# ===========================================================================
class SMA(db.Model):
    """
    A Shared Ministry Agreement
    """
    sma_org_name = db.ReferenceProperty()

    # "Name of Group/Ministry:"
    sma_name = db.StringProperty()

    # "Purpose/Description of Group/Ministry:"
    sma_purpose_t = db.TextProperty()

    # Co-leaders and contact information (email and phone):
    # sma_leaders = db.ReferenceProperty(Person, collection_name='leaders')
    sma_leaders = db.TextProperty()
    
    # Members (please list at least 3, in addition to co-leaders):
    # sma_members = db.ReferenceProperty(Person, collection_name='members')
    sma_members = db.TextProperty()
    
    # Section 2: How does this group connect with the rest of ORUUC?
    # (If this section is confusing, it may be easier to complete in
    # conversation with staff -- that's OK!)

    #     Staff Liaison (if known):
    #         dropdown: Jake Morill, 
    #                   Tandy Scheffler, 
    #                   Wendell Werner, 
    #                   Debbie Crider
    sma_staff = db.ReferenceProperty(Person, collection_name='sm_staff')

    # Coordinating Council Liason (if known):
    # sma_council = db.ReferenceProperty(Person, collection_name='council')
    sma_council = db.TextProperty()
    
    sma_support_t = db.TextProperty()

    #     Which of the Strategic Plan's goals or objectives does this
    #     group/ministry PRIMARILY pursue?
    #
    #         choice: Goal 1
    #                 Goal 2
    #                 Goal 3
    #                 Goal 4
    #                 Goal 5
    #                 Goal 6
    #                 Goal 7
    sma_goal = db.StringProperty()

    # How does this ministry pursue that goal/objective?
    sma_goalhow_t = db.TextProperty()

    # What other Strategic Plan goals or objectives does this group/ministry
    # pursue?
    #  list of checkboxes: one for each goal with text of each goal
    sma_altgoals = db.StringListProperty()

    # With what other ORUUC groups (if any) does your group interact?
    sma_other_groups_t = db.TextProperty()

    #     How does this group share what it is doing with the wider
    #     congregation?
    #     (Check all that apply.)
    #  checkbox list: Exponent, What's Happening, Posters, etc.
    sma_comm = db.StringListProperty()
    sma_comm_other = db.StringProperty()
    
    # Are there safety/liability concerns? If so please list:
    sma_safety_t = db.TextProperty()

    # Section 3: GROUP PROCESS
    
    # Time Period
    #   <radio> Church Year/Ongoing (July 1 - June 30)
    #   <radio> Other, please specify: <input>
    sma_cycle = db.StringProperty()
    sma_cycle_other = db.StringProperty()
    
    # How do individuals join and leave the group/ministry?
    sma_join_t = db.TextProperty()

    # Preferred meeting days/dates (if known) and place:
    sma_timeloc_t = db.TextProperty()

    # How does the group grow new leaders and plan for leadership
    # succession?
    # checkbox list: (see DESIGN.txt)
    sma_succession = db.StringListProperty()
    sma_succ_other_val_t = db.StringProperty()
    
    # What does the group do or plan to do to minimize burn-out?
    # checkbox list: (see DESIGN.txt)
    sma_burnout = db.StringListProperty()
    sma_burn_other_val_t = db.StringProperty()
    
    # How does the group handle or plan to handle conflict?
    sma_conflict = db.StringListProperty()
    sma_conf_other_val = db.StringProperty()
    
    # Upon completion, or at milestones, how will you
    # celebrate/recognize/thank people, or provide closure?
    sma_celebrate_t = db.TextProperty()

    # SECTION 4: GROUP FUNCTIONS--LEARN, SERVE, CARE

    # Strong religious groups, while perhaps focusing on one of these
    # three functions, attend to all three. Group members learn
    # together, serve the wider community (church or beyond), and care
    # for each other in times of need. ORUUC groups are asked to
    # attend to all three functions. Staff can assist you in
    # completing this section, if that would be helpful.
    # Which of the three functions is primary for your Group/Ministry?
    # <radio>: Learn, Serve, Care
    sma_function = db.StringProperty()

    # How do you incorporate the other two functions in the life of your
    # Group/Ministry?
    sma_altfunc_t = db.TextProperty()

    # Section 5: Resources & Support

    # What ORUUC resources does your group/ministry need?

    # Staff Support:
    # (Please identify staff person, their role, and approximate number of
    # hours.)
    sma_resource_staff_t = db.TextProperty()

    # Financial REsources
    # (Describe briefly any financial needs.)
    sma_resource_money_t = db.TextProperty()

    # Facilities:
    # (Room needs, storage needs)
    sma_resource_room_t = db.TextProperty()
    sma_resource_storage_t = db.TextProperty()
    
    # Training
    # (Is there any special training or leadership development your group
    # needs?)
    sma_resource_train_t = db.TextProperty()

    # Communication needs such as church newsletter, What's Happening,
    # Calendar, Facebook groups, etc.:
    sma_resource_comm_t = db.TextProperty()
    
    # Church Policies/Guidelines:
    # (Identify any polciies or guidelines that may need to be created or
    # clarified.)
    sma_clarification_t = db.TextProperty()

    # What concerns/problems do you have or anticipate?
    sma_concerns_t = db.TextProperty()

    # How could the "Shared Ministry Agreement" process be improved?
    sma_improve_t = db.TextProperty()

    # Track annual reviews
    sma_annual_review = db.StringProperty()

    # sma_adder = db.UserProperty(auto_current_user_add=True)
    # sma_added = db.DateTimeProperty(auto_now_add=True)
    sma_updater = db.UserProperty(auto_current_user=True)
    sma_updated = db.DateTimeProperty(auto_now=True)
    sma_hidden = db.BooleanProperty(False)
    
# ===========================================================================
def dt_format():
    return '%a, %b %d, %Y, at %H:%M:%S'

# ===========================================================================
def eastern_time(dt):
    tup = dt.timetuple()
    tz = estedt.Eastern_tzinfo()
    return datetime.fromtimestamp(time.mktime(tup), tz)

# ===========================================================================
def last_review_year(group):
    z = group.sma_annual_review.split()
    if 0 < len(z):
        z.sort()
        return z[-1]
    else:
        return ""
    
# ===========================================================================
def staff_list():
    rval = [' '.join([p.p_firstname, p.p_lastname])
            for p in Person.all()
            if 'Staff' in p.p_role]
    return rval
    
# ===========================================================================
class GenericPage(webapp2.RequestHandler):
    # ----------------------------------------------------------------------
    def add_error(self, msg):
        try:
            self.errors.append(msg)
        except:
            self.errors = [msg]
            
    # ----------------------------------------------------------------------
    def get_errors(self):
        try:
            return self.errors
        except:
            return []
            
    # ----------------------------------------------------------------------
    def get_domain(self):
        spath = self.request.path.split('/')
        domain = spath.pop(1)
        return domain
    
    # ----------------------------------------------------------------------
    def get_action(self):
        spath = self.request.path.split('/')
        domain = spath.pop(1)
        try:
            action = spath.pop(1)
        except:
            action = 'list'
        if action == '':
            action = 'list'
        return action
    
# ===========================================================================
class SmaPage(GenericPage):
    # ----------------------------------------------------------------------
    def get(self):
        domain = self.get_domain()
        action = self.get_action()
        which = self.request.get('group_id')

        logging.info('SmaPage.get: domain = %s; action = %s; which = %s'
                     % (domain, action, which))
        if domain != '' and domain != 'group':
            self.add_error('Wrong domain')
        if action not in ['list', 'new', 'view', 'update', 'hide', 'delete']:
            self.add_error('Invalid action: %s' % action)
        if action in ['view', 'update', 'hide', 'delete'] and which == '':
            self.add_error('Action %s requires a group id' % action)

        if action == 'list':
            glist = []
            for g in SMA.all():
                g.sma_updated = eastern_time(g.sma_updated)
                g.sma_annual_review = last_review_year(g)
                glist.append(g)

            slist = sorted(glist, key=lambda gr: gr.sma_name.lower())
            template_values = {
                'action': action,
                'admin': users.is_current_user_admin(),
                'writeable': db.WRITE_CAPABILITY.is_enabled(),
                'dt_format': dt_format(),
                'errors': self.get_errors(),
                'groups': slist,
                'logout': users.create_logout_url(self.request.uri),
                'user': users.get_current_user(),
                'version': os.environ['CURRENT_VERSION_ID']
                }
            template = jinja_environment.get_template('sma.html')
            self.response.out.write(template.render(template_values))
            
        elif action == 'new':
            ld = self.list_dict()
            staff_name = ''
            group_id = ''
            cache = self.get_cache()
            template_values = {
                'action': action,
                'cache': cache,
                'errors': self.get_errors(),
                'comm_list': ld['comm_list'],
                'cycle_d': ld['cycle_d'],
                'dt_format': dt_format(),
                'func_l': ld['func_l'],
                'goal_list': ld['goal_list'],
                'group_id': group_id,
                'staff_l': staff_list(),
                'staff_name': staff_name,
                'succ_l': ld['succ_l'],
                'burnout_l': ld['burnout_l'],
                'conflict_l': ld['conflict_l'],
                'this_year': time.strftime('%Y'),
                }
            template = jinja_environment.get_template('sma.html')
            self.response.out.write(template.render(template_values))

        elif action == 'view':
            if not which.isdigit():
                self.add_error("Can't look up non-numeric group id")
                self.redirect("/")
            else:
                gr = SMA.get_by_id(int(which))
                if gr.sma_staff != None:
                    staff_name = ' '.join([gr.sma_staff.p_firstname,
                                           gr.sma_staff.p_lastname])
                else:
                    staff_name = ''
                logging.info("SmaPage.get: %s = %s; %s = %s"
                             % ("gr.sma_cycle", gr.sma_cycle,
                                "gr.sma_cycle_other", gr.sma_cycle_other))
                ld = self.list_dict()
                template_values = {
                    'action': action,
                    'errors': self.get_errors(),
                    'group': gr,
                    'func_l': ld['func_l'],
                    'goal_list': ld['goal_list'],
                    'staff_name': staff_name,
                    'dt_format': dt_format(),
                    }
                template = jinja_environment.get_template('sma.html')
                self.response.out.write(template.render(template_values))
                
        elif action == 'update':
            grid = self.request.get('group_id')
            gr = self.get_cache(grid)
            logging.info("SmaPage.get: burn other = %s"
                         % gr['sma_burn_other_val_t'])
            ld = self.list_dict()
            if gr['sma_staff'] != None and gr['sma_staff'] != '':
                staff_name = ' '.join([gr['sma_staff'].p_firstname,
                                       gr['sma_staff'].p_lastname])
            else:
                staff_name = ''
                
            template_values = {
                'action': action,
                'cache': gr,
                'errors': self.get_errors(),
                'group_id': grid,
                'comm_list': ld['comm_list'],
                'cycle_d': ld['cycle_d'],
                'func_l': ld['func_l'],
                'goal_list': ld['goal_list'],
                'succ_l': ld['succ_l'],
                'burnout_l': ld['burnout_l'],
                'conflict_l': ld['conflict_l'],
                'staff_l': staff_list(),
                'staff_name': staff_name,
                'this_year': time.strftime('%Y'),
                }
            template = jinja_environment.get_template('sma.html')
            self.response.out.write(template.render(template_values))
            
        elif action == 'hide':
            logging.info("SmaPage.get: which to hide = %s" % which)
            gr = SMA.get_by_id(int(which))
            gr.sma_hidden = True
            gr.put()
            self.redirect("/")
            
        elif action == 'unhide':
            logging.info("SmaPage.get: which to hide = %s" % which)
            gr = SMA.get_by_id(int(which))
            gr.sma_hidden = False
            gr.put()
            self.redirect("/")
            
        elif action == 'delete':
            logging.info("SmaPage.get: which to delete = %s" % which)
            grid = self.request.get("group_id")
            # gr = SMA.get_by_id(int(grid))
            template_values = {
                'action': action,
                'cache': self.get_cache(grid),
                'errors': self.get_errors(),
                'group_id': grid,
                }
            template = jinja_environment.get_template('sma.html')
            self.response.out.write(template.render(template_values))

        else:
            self.add_error('Invalid action: %s' % action)
            glist = []
            for g in SMA.all():
                g.sma_updated = eastern_time(g.sma_updated)
                glist.append(g)
            template_values = {
                'action': 'list',
                'admin': users.is_current_user_admin(),
                'dt_format': dt_format(),
                'errors': self.get_errors(),
                'groups': glist,
                'logout': users.create_logout_url(self.request.uri),
                'user': users.get_current_user(),
                }
            template = jinja_environment.get_template('sma.html')
            self.response.out.write(template.render(template_values))

    # ----------------------------------------------------------------------
    def post(self):
        action = self.request.get('action')
        logging.info("SmaPage.post: action = %s" % (action))
        if self.request.get('cancel') == 'cancel':
            self.redirect("/")
            return

        submit = self.request.get('submit')
        if submit == "Cancel":
            self.redirect("/group")
            return
        
        # validate fields
        if action != 'delete':
            pass

        if 0 < len(self.get_errors()):
            self.get()
        elif action == 'new':
            gr = self.sma_from_request()
            gr.put()
            
            s_continue = self.request.get('submit_continue')
            s_group = self.request.get('submit_group')
            s_logout = self.request.get('submit_logout')
            if 'logout' in s_logout:
                self.redirect(users.create_logout_url(self.request.uri))
            elif 'group' in s_group:
                self.redirect("/")
            else:
                self.redirect("/group/update?id=%d" % (gr.key().id()))
            return
        
        elif action == 'view':
            pass
        elif action == 'update':
            grid = self.request.get('group_id')
            logging.info("SmaPage.post: burn other = %s"
                         % self.request.get('sma_burn_other_val_t'))
            logging.info("SmaPage.post: sma_cycle = %s"
                         % self.request.get('sma_cycle'))
            logging.info("SmaPage.post: sma_cycle_other = %s"
                         % self.request.get('sma_cycle_other'))
            gr = SMA.get_by_id(int(grid))
            gr = self.sma_from_request(gr)
            gr.put()

            s_continue = self.request.get('submit_continue')
            s_group = self.request.get('submit_group')
            s_logout = self.request.get('submit_logout')
            if 'logout' in s_logout:
                self.redirect(users.create_logout_url(self.request.uri))
            elif 'group' in s_group:
                self.redirect("/")
            else:
                self.redirect("/group/update?group_id=%d" % (gr.key().id()))
            return
            
        elif action == 'delete':
            grid = self.request.get('group_id')
            gr = SMA.get_by_id(int(grid))
            gr.delete()
            self.redirect("/group/list")

        elif action == 'archive':
            pass
        else:
            self.redirect('/group')

    # ----------------------------------------------------------------------
    def get_cache(self, gid=None):
        rval = {'sma_name': '',
                'sma_purpose_t': '',
                'sma_leaders': '',
                'sma_members': '',
                'sma_staff': None,
                'sma_council': '',
                'sma_support_t': '',
                'sma_goal': '',
                'sma_goalhow_t': '',
                'sma_altgoals': '',
                'sma_other_groups_t': '',
                'sma_comm': '',
                'sma_comm_other': '',
                'sma_safety_t': '',
                'sma_cycle': '',
                'sma_cycle_other': '',
                'sma_join_t': '',
                'sma_timeloc_t': '',
                'sma_succession': '',
                'sma_succ_other_val_t': '',
                'sma_burnout': '',
                'sma_burn_other_val_t': '',
                'sma_conflict': '',
                'sma_conf_other_val': '',
                'sma_celebrate_t': '',
                'sma_function': '',
                'sma_altfunc_t': '',
                'sma_resource_staff_t': '',
                'sma_resource_money_t': '',
                'sma_resource_room_t': '',
                'sma_resource_storage_t': '',
                'sma_resource_train_t': '',
                'sma_resource_comm_t': '',
                'sma_clarification_t': '',
                'sma_concerns_t': '',
                'sma_improve_t': '',
                'sma_annual_review': '',
                }

        try:
            rval = self.cache
        except AttributeError:
            if gid == None:
                gid = self.request.get('group_id')
            if gid != '':
                g = SMA.get_by_id(int(gid))
                rval = {'sma_name': g.sma_name,
                        'sma_purpose_t': g.sma_purpose_t,
                        'sma_leaders': g.sma_leaders,
                        'sma_members': g.sma_members,
                        'sma_staff': g.sma_staff,
                        'sma_council': g.sma_council,
                        'sma_support_t': g.sma_support_t,
                        'sma_goal': g.sma_goal,
                        'sma_goalhow_t': g.sma_goalhow_t,
                        'sma_altgoals': g.sma_altgoals,
                        'sma_other_groups_t': g.sma_other_groups_t,
                        'sma_comm': g.sma_comm,
                        'sma_comm_other': g.sma_comm_other,
                        'sma_safety_t': g.sma_safety_t,
                        'sma_cycle': g.sma_cycle,
                        'sma_cycle_other': g.sma_cycle_other,
                        'sma_join_t': g.sma_join_t,
                        'sma_timeloc_t': g.sma_timeloc_t,
                        'sma_succession': g.sma_succession,
                        'sma_succ_other_val_t': g.sma_succ_other_val_t,
                        'sma_burnout': g.sma_burnout,
                        'sma_burn_other_val_t': g.sma_burn_other_val_t,
                        'sma_conflict': g.sma_conflict,
                        'sma_conf_other_val': g.sma_conf_other_val,
                        'sma_celebrate_t': g.sma_celebrate_t,
                        'sma_function': g.sma_function,
                        'sma_altfunc_t': g.sma_altfunc_t,
                        'sma_resource_staff_t': g.sma_resource_staff_t,
                        'sma_resource_money_t': g.sma_resource_money_t,
                        'sma_resource_room_t': g.sma_resource_room_t,
                        'sma_resource_storage_t': g.sma_resource_storage_t,
                        'sma_resource_train_t': g.sma_resource_train_t,
                        'sma_resource_comm_t': g.sma_resource_comm_t,
                        'sma_clarification_t': g.sma_clarification_t,
                        'sma_concerns_t': g.sma_concerns_t,
                        'sma_improve_t': g.sma_improve_t,
                        'sma_annual_review': g.sma_annual_review,
                        }
        return rval

    # ----------------------------------------------------------------------
    def sma_from_request(self, start=None):
        if start == None:
            gr = SMA()
        else:
            gr = start
            
        gr.sma_updater = users.get_current_user()
        gr.sma_updated = datetime.now()
        gr.sma_name = self.request.get('sma_name')
        gr.sma_purpose_t = self.request.get('sma_purpose_t')
        gr.sma_leaders = self.request.get('sma_leaders')
        gr.sma_members = self.request.get('sma_members')
        gr.sma_staff = self.person_handle(fullname=self.request.get('sma_staff'))
        gr.sma_council = self.request.get('sma_council')
        gr.sma_support_t = self.request.get('sma_support_t')
        gr.sma_goal = self.request.get('sma_goal')
        gr.sma_goalhow_t = self.request.get('sma_goalhow_t')
        gr.sma_altgoals = self.request.get_all('sma_altgoals')
        gr.sma_other_groups_t = self.request.get('sma_other_groups_t')
        gr.sma_comm = self.request.get_all('sma_comm')
        gr.sma_comm_other = self.request.get('sma_comm_other')
        gr.sma_safety_t = self.request.get('sma_safety_t')
        gr.sma_cycle = self.request.get('sma_cycle')
        gr.sma_cycle_other = self.request.get('sma_cycle_other')
        gr.sma_join_t = self.request.get('sma_join_t')
        gr.sma_timeloc_t = self.request.get('sma_timeloc_t')
        gr.sma_succession = self.request.get_all('sma_succession')
        gr.sma_succ_other_val_t = self.request.get('sma_succ_other_val_t')
        gr.sma_burnout = self.request.get_all('sma_burnout')
        gr.sma_burn_other_val_t = self.request.get('sma_burn_other_val_t')
        gr.sma_conflict = self.request.get_all('sma_conflict')
        gr.sma_conf_other_val = self.request.get('sma_conf_other_val')
        gr.sma_celebrate_t = self.request.get('sma_celebrate_t')
        gr.sma_function = self.request.get('sma_function')
        gr.sma_altfunc_t = self.request.get('sma_altfunc_t')
        gr.sma_resource_staff_t = self.request.get('sma_resource_staff_t')
        gr.sma_resource_money_t = self.request.get('sma_resource_money_t')
        gr.sma_resource_room_t = self.request.get('sma_resource_room_t')
        gr.sma_resource_storage_t = self.request.get('sma_resource_storage_t')
        gr.sma_resource_train_t = self.request.get('sma_resource_train_t')
        gr.sma_resource_comm_t = self.request.get('sma_resource_comm_t')
        gr.sma_clarification_t = self.request.get('sma_clarification_t')
        gr.sma_concerns_t = self.request.get('sma_concerns_t')
        gr.sma_improve_t = self.request.get('sma_improve_t')
        this_year = time.strftime('%Y')
        if self.request.get('sma_annual_review'):
            if None == gr.sma_annual_review:
                gr.sma_annual_review = this_year
            elif this_year not in gr.sma_annual_review:
                gr.sma_annual_review += " " + this_year
        else:
            if None == gr.sma_annual_review:
                gr.sma_annual_review = ''
            elif this_year in gr.sma_annual_review:
                yl = gr.sma_annual_review.split()
                yl.remove(this_year)
                gr.sma_annual_review = ' '.join(yl)
                
        return gr
    
    # ----------------------------------------------------------------------
    def person_handle(self, **kw):
        rval = None
        if 'fullname' in kw.keys():
            logging.info("person_handle: fullname = '%s'" % kw['fullname'])
            try:
                (first, last) = kw['fullname'].split('_')
                for p in Person.all():
                    if p.p_firstname == first and p.p_lastname == last:
                        rval = p
            except ValueError:
                pass  # rval is already set to None
        return rval

    # ----------------------------------------------------------------------
    def list_dict(self):
        rval = {
            'goal_list': ["""
            Goal 1: We embrace our common vision and the Unitarian
            Universalist principles while encouraging and supporting our
            DIVERSITY.
            ""","""
            Goal 2: Our spiritual and religious life is enhanced by
            quality WORSHIP and MUSIC.
            ""","""
            Goal 3: We foster the lifelong FAITH FORMATION of spiritual
            and ethical Unitarian Universalists.
            ""","""
            Goal 4: We commit to transform the world around us through
            acts of compassion, love and SOCIAL JUSTICE.
            ""","""
            Goal 5: Our PASTORAL CARE is shared, intentional, and
            comprehensive.
            ""","""
            Goal 6: We have a loving, safe, and lively COMMUNITY that
            values belonging and connection.
            ""","""
            Goal 7: Our campus (FACILITIES) is this outward expression
            of our mission.
            """],

            'comm_list': ["Exponent",
                          "What's Happening",
                          "Posters",
                          "Facebook Group",
                          "Church Website",
                          "Announcements during worship",
                          "Wayside pulpit",
                          "Local news media",
                          "Other, please specify:"],

            'cycle_d': {'fiscal': 'Church Year/Ongoing (July 1 - June 30)',
                        'other': 'Other, please specify:'},

            'succ_l': ['Designate a chair elect each year',
                       'Rotate leadership among group members',
                       'Have co-leaders who share the role',
                       'Other, please specify:'],

            'burnout_l': ['Culture where saying "no" is okay',
                         'Check-in at meetings',
                         'Opportunity to recommit or step down at'
                         + ' least once a year',
                         'Opportunities for fun alongside work',
                         'Share leadership',
                         'Other, please specify:'],

            'conflict_l': ['Have a group covenant',
                          'Learn and practice non-violent communication',
                          'Assume goodwill',
                          'Ask for help from staff if not resolved',
                          'Other, please specify:'],

            'func_l': ["learn", "serve", "care"],
            }
        return rval

# ===========================================================================
class DebugPage(webapp2.RequestHandler):
    # ----------------------------------------------------------------------
    def get(self):
        self.response.headers['Content-Type'] = 'text/html'
        self.response.out.write('<h1>DEBUG</h1>')
        self.response.out.write("<br>id = '%s'" %
                                self.request.get('id'))
        self.response.out.write("<br>dir = '%s'" %
                                dir(self.request))
        self.response.out.write("<br>split path = '%s'"
                                % self.request.path.split('/'))
        spath = self.request.path.split('/')
        domain = spath.pop(1)
        action = spath.pop(1)
        which = self.request.get('id')
        self.response.out.write("<br>domain = '%s'" % domain)
        self.response.out.write("<br>action = '%s'" % action)
        self.response.out.write("<br>which = %s" % which)
        
        u = users.get_current_user()
        u = self.request
        z = ''
        for item in dir(u):
            if item in ['postvars', 'queryvars', 'str_postvars',
                        'str_queryvars']:
                continue
            l = '%s type=%s val=%s' % (item,
                                       type(u.__getattribute__(item)),
                                       u.__getattribute__(item))
            z += l + "\n"
        # z += "nickname = %s" % u.nickname()
        
        self.response.out.write("<pre>%s</pre>" % z)
        self.response.out.write("<hr>")
        for key in self.request.environ.keys():
            self.response.out.write("<br>%s='%s'"
                                    % (key, self.request.environ[key]))

        self.response.out.write('<br><center><a href="')
        self.response.out.write(users.create_logout_url(self.request.uri))
        self.response.out.write('">logout</a></center>')

# ===========================================================================
class PersonPage(GenericPage):
    """
    supported URLs:
    .../person                 => list all Person records
    .../person/new             => create new Person record
    .../person/view?id=<id>    => display Person <id>
    .../person/update?id=<id>  => update Person <id>
    .../person/delete?id=<id>  => delete Person <id>
    """
    # ----------------------------------------------------------------------
    def get(self):
        if not users.is_current_user_admin():
            self.redirect("/")

        domain = self.get_domain()
        action = self.get_action()

        which = self.request.get('id')
        if domain != 'person':
            self.add_error('Wrong domain')
        if action not in ['list', 'new', 'view', 'update', 'delete']:
            self.add_error('Invalid action: %s' % action)
        if action in ['view', 'update', 'delete'] and which == '':
            self.add_error('Action %s requires a person id' % action)

        # logging.info('in get(2): action = %s' % self.request.get('action'))
        
        if action == 'list':
            plist = []
            for p in Person.all():
                p.p_updated = eastern_time(p.p_updated)
                rlist = [str(role) for role in p.p_role]
                p.p_role = rlist
                plist.append(p)
                
            template_values = {
                'action': action,
                'errors': self.get_errors(),
                'plist': plist,
                }
            template = jinja_environment.get_template('person.html')
            self.response.out.write(template.render(template_values))
        elif action == 'new':
            plist = []
            cache = self.get_cache()
            logging.info('PersonPage.get - retrieved cache: %s'
                         % cache)
            template_values = {
                'errors': self.get_errors(),
                'cache': cache,
                'action': action,
                }
            template = jinja_environment.get_template('person.html')
            self.response.out.write(template.render(template_values))
        elif action == 'update':
            pid = self.request.get('id')
            plist = [ Person.get_by_id(int(pid)) ]
            cache = self.get_cache()
            logging.info('PersonPage.get - cache: %s' % cache)
            template_values = {
                'action': action,
                'cache': cache,
                'errors': self.get_errors(),
                'id': pid,
                }
            template = jinja_environment.get_template('person.html')
            self.response.out.write(template.render(template_values))
        elif action == 'delete':
            pid = self.request.get('id')
            plist = [ Person.get_by_id(int(pid)) ]
            template_values = {
                'action': action,
                'cache': self.get_cache(),
                'errors': self.get_errors(),
                'id': pid,
                }
            template = jinja_environment.get_template('person.html')
            self.response.out.write(template.render(template_values))
        else:
            self.add_error('Invalid action: %s' % action)
            plist = []
            for p in Person.all():
                p.p_updated = eastern_time(p.p_updated)
                plist.append(p)
            template_values = {
                'action': 'list',
                'errors': self.get_errors(),
                'plist': plist,
                }
            template = jinja_environment.get_template('person.html')
            self.response.out.write(template.render(template_values))

    # ----------------------------------------------------------------------
    def get_cache(self):
        rval = {'fname': '', 'lname': '', 'phone': '',
                'email': '', 'gname': '', 'roles': []}
        try:
            rval = self.cache
        except AttributeError:
            pid = self.request.get('id')
            if pid != '':
                p = Person.get_by_id(int(pid))
                rval = {'fname': p.p_firstname,
                        'lname': p.p_lastname,
                        'phone': p.p_phone,
                        'email': p.p_email,
                        'gname': p.p_username,
                        'roles': p.p_role}
        return rval

    # ----------------------------------------------------------------------
    def post(self):
        action = self.request.get('action')
        if self.request.get('submit') == "Cancel":
            self.redirect("/person")
            return

        self.cache = {}
        for field in ['fname', 'lname', 'phone', 'email', 'gname', 'roles']:
            self.cache[field] = self.request.get(field)
            logging.info("PersonPage.post - caching '%s' = '%s'" %
                         (field, self.cache[field]))

        # Don't validate fields for a delete request since we're just
        # deleting the record
        if action != 'delete':
            if ' ' in self.request.get('fname'):
                self.add_error('First name may not contain spaces')
            if ' ' in self.request.get('lname'):
                self.add_error('Last name may not contain spaces')
            if not self.valid_phone_number(self.request.get('phone')):
                self.add_error('Phone number is not valid')
            if not self.valid_email_address(self.request.get('email')):
                self.add_error('Email address is not valid')

        if 0 < len(self.get_errors()):
            self.get()
        elif action == 'new':
            p = Person()
            p.p_updater = users.get_current_user()
            p.p_updated = datetime.now()
            p.p_firstname = self.request.get('fname')
            p.p_lastname = self.request.get('lname')
            p.p_phone = self.request.get('phone')
            p.p_email = self.request.get('email')
            p.p_username = self.request.get('gname')
            p.p_role = self.request.get_all('roles')
            logging.info('p_role = %s' % p.p_role)
            p.put()
            self.redirect("/person")
        elif action == 'update':
            person_id = self.request.get('id')
            p = Person.get_by_id(int(person_id))
            p.p_updater = users.get_current_user()
            p.p_updated = datetime.now()
            p.p_firstname = self.request.get('fname')
            p.p_lastname = self.request.get('lname')
            p.p_phone = self.request.get('phone')
            p.p_email = self.request.get('email')
            p.p_username = self.request.get('gname')
            p.p_role = self.request.get_all('roles')
            p.put()
            self.redirect("/person")
        elif action == 'delete':
            person_id = self.request.get('id')
            p = Person.get_by_id(int(person_id))
            p.delete()
            self.redirect("/person/list")
        else:
            self.redirect("/person")
            
    # ----------------------------------------------------------------------
    def valid_phone_number(self, phone):
        if re.match(r'\d{3}[-.]\d{3}[-.]\d{4}$', phone.strip()):
            return True
        else:
            return False
        
    # ----------------------------------------------------------------------
    def valid_email_address(self, email):
        if re.match(r'^[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+$', email.strip()):
            return True
        else:
            return False
        
# ===========================================================================
class ThankYouPage(webapp2.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.out.write('This is ThankYouPage')
        
app = webapp2.WSGIApplication([('/', SmaPage),
                               ('/group', SmaPage),
                               ('/group/.*', SmaPage),
                               ('/debug/.*', DebugPage),
                               ('/person', PersonPage),
                               ('/person/.*', PersonPage),
                               ('/thankyou', ThankYouPage)],
                              debug=True)
